package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.CustomBottom;
import com.myk.game.gobangchess.History;
import com.myk.game.gobangchess.Player;
import com.myk.game.gobangchess.Sign;
import com.myk.game.gobangchess.ai.shock.If_go_push;
import com.myk.game.gobangchess.constants.BoardStyleData;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.rooms.absrooms.AbsOneTwoTwoTwoStepRoom;
import com.myk.game.gobangchess.signs.ColorSign;
import com.myk.game.gobangchess.signs.GroundSign;
import com.myk.game.gobangchess.utils.GridsUtils;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 《星光六连棋》
 * 1.落子模式为1222…，六连为胜
 * 2.每步第1手棋和对方上回合任意1子同线，第2手棋与自己第1手棋同线
 */
public class Connect6InTheLineRoom extends AbsOneTwoTwoTwoStepRoom {

    public static final String STAR_LIGHT_COLOR = "#66FFFF30"; //星光颜色
    public static final String BG_COLOR = "#55002260"; //背景颜色
    public static final String ED_COLOR = "#FF224466"; //边框颜色

    private List<int[]> lastPoint = new ArrayList<>(); //长度为3的数组，row，col，value
    private int state = 0; //0：本回合还未落子， 1：本回合已落一子

    private final List<His> hisList = new ArrayList<>(); //记录当前状态，用于动态按钮撤销还原状态

    public Connect6InTheLineRoom(String roomName) {
        super(roomName, "群友itt设计的规则，巧妙结合了三款逆界热门新棋的特点（王马连星、双线五子棋、六子棋）。", "星光六连棋", BoardStyleData.getGoBangStyle(19, 19), true, true);
    }

    @Override
    public String getRuleText() {
        return "开局第一回合黑方先在棋盘任意位置落1枚棋子，\n之后白黑双方轮流每回合落下2枚棋子。\n" +
                "棋子落下后会往直线斜线8个方向投射光线，\n后续棋子只能落在光线所在的格子上。\n" +
                "每回合第1手棋落在对方的星光上并熄灭对方星光，\n第2手棋落在自己的星光上。\n" +
                "落子后形成六子连珠获胜！";
    }

    @Override
    public String getGameInfo() {
        signList.clear();
        signList.add(new GroundSign(getIndex(0, 0), getIndex(curGrids.length - 1, curGrids[0].length - 1), BG_COLOR, ED_COLOR, 3f, 0, 0));
        signList.addAll(tempPointSigns);
        return super.getGameInfo();
    }

    @Override
    public void doRule(int row, int col, int value) {
        if (curGrids[row][col] != 0) {
            return;
        }
        if ((step == 0 && hisList.size() == 1) || hisList.size() == 2) {
            return;
        }
        if (step == 0) { //先手第一步逻辑
            recordHis(); //记录之前的状态数据
            curGrids[row][col] = value;
            firstPoint = new int[]{row, col, value}; //用于落子提示绿色框的判断
            lastPoint = new ArrayList<int[]>();
            lastPoint.add(new int[]{row, col, value});
            updateTempPointSigns();
            updateCustomButtons();
            noticeAllRefreshGameInfo();
        }
        else {
            if (isOnSameLine(row, col)) {
                recordHis(); //记录之前的状态数据
                curGrids[row][col] = value;
                if (state == 0) {  //本回合第一步
                    WinState winState = checkWin(row, col);
                    if (winState != null) {
                        stepAdd();
                        doOver(winState.winMode, winState.winMsg);
                    }
                    else {
                        firstPoint = new int[]{row, col, value}; //用于落子提示绿色框的判断
                        lastPoint = new ArrayList<>(); //重新构建lastPoint容器
                        lastPoint.add(new int[]{row, col, value});
                        updateTempPointSigns();
                        state = 1;
                        updateCustomButtons();
                        noticeAllRefreshGameInfo();
                    }
                }
                else { //本回合第二步
                    secondPoint = new int[]{row, col, value};
                    lastPoint.add(new int[]{row, col, value});
                    updateTempPointSigns();
                    state = 0;
                    WinState winState = checkWin(row, col);
                    if (winState != null) {
                        stepAdd();
                        doOver(winState.winMode, winState.winMsg);
                    }
                    else {
                        updateCustomButtons();
                    }
                    noticeAllRefreshGameInfo();
                }
            }
        }
    }

    @Override
    public void resetGrids() {
        lastPoint = null;
        state = 0;
        hisList.clear();
        super.resetGrids();
    }

    @Override
    protected WinState checkWin(int row, int col) {
        int winValue = 0;
        int[][] dxdy = {{1, 0}, {-1, 1}, {0, 1}, {1, 1}};
        for (int i = 0; i < dxdy.length; i++) {
            int dx = dxdy[i][0], dy = dxdy[i][1];
            int length = getJudgeLength(row, col, dx, dy) + getJudgeLength(row, col, -dx, -dy) - 1;
            if (length >= 6) {
                winValue = (curGrids[row][col] + 1) % 2 + 1;
            }
        }

        boolean gridFull = GridsUtils.getDataCount(curGrids, 0) == 0;

        if (winValue == 1) {
            return new WinState(WinMode.BLACK_WIN, player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
        }
        else if (winValue == 2) {
            return new WinState(WinMode.WHITE_WIN, player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
        }
        else if (gridFull) {
            return new WinState(WinMode.BOTH_DRAW, player_black.getNickNameOrTemp() + "-黑棋战平" + player_white.getNickNameOrTemp() + "-白棋");
        }
        else {
            return null;
        }
    }

    @Override
    public void noticeBlackMove() {
        updateCustomButtons();
        super.noticeBlackMove();
    }

    @Override
    public void noticeWhiteMove() {
        updateCustomButtons();
        super.noticeWhiteMove();
    }

    @Override
    public void doOver(int winMode, String winMsg) {
        if (player_black != null){
            player_black.clearCustomBottom();
            player_black.dispatchCustomBottom();
        }
        if (player_white != null){
            player_white.clearCustomBottom();
            player_white.dispatchCustomBottom();
        }
        super.doOver(winMode, winMsg);
    }

    private boolean isOnSameLine(int row, int col) {
        /*先手第一步不会调用该方法*/

        if (state == 1 || step == 1) {  //第二回合的第一步 和 自己回合的第二步 都只会有1个子棋的星光
            int lastRow = lastPoint.get(0)[0];
            int lastCol = lastPoint.get(0)[1];

            if (lastRow == row || lastCol == col) {
                return true;
            }
            if (Math.abs(lastRow - row) == Math.abs(lastCol - col)) {
                return true;
            }
        }
        else { //会有2个棋子的星光
            for (int i = 0; i < 2; i++) {
                int lastRow = lastPoint.get(i)[0];
                int lastCol = lastPoint.get(i)[1];

                if (lastRow == row || lastCol == col) {
                    return true;
                }
                if (Math.abs(lastRow - row) == Math.abs(lastCol - col)) {
                    return true;
                }
            }
        }

        return false;
    }

    private void updateCustomButtons() {
        if (step == 0){
            if (player_black != null && hisList.size() == 1) {
                player_black.registerCustomBottom(new CustomBottom(this, "撤回", player -> {
                    restoreHis();
                    noticeAllRefreshGameInfo();
                    player_black.removeCustomBottom(player_black.findCustomBottomByTitle(this, "确认落子"));
                    if (hisList.size() == 0) {
                        player_black.removeCustomBottom(player_black.findCustomBottomByTitle(this, "撤回"));
                    }
                    player_black.dispatchCustomBottom();
                }));
                player_black.registerCustomBottom(new CustomBottom(this, "确认落子", player -> {
                    hisList.clear();
                    stepAdd();
                    noticeChangeMove();
                    if (player_black != null) {
                        player_black.clearCustomBottom();
                        player_black.dispatchCustomBottom();
                    }
                }));
            }
            else {
                if (player_black != null){
                    player_black.clearCustomBottom();
                    player_black.dispatchCustomBottom();
                }
            }
        }
        else {
            if (cur == 1) {
                if (player_black != null) {
                    if (hisList.size() == 0){
                        player_black.clearCustomBottom();
                        player_black.dispatchCustomBottom();
                    }
                    if (hisList.size() >= 1){
                        player_black.registerCustomBottom(new CustomBottom(this, "撤回", player -> {
                            restoreHis();
                            noticeAllRefreshGameInfo();
                            player_black.removeCustomBottom(player_black.findCustomBottomByTitle(this, "确认落子"));
                            if (hisList.size() == 0) {
                                player_black.removeCustomBottom(player_black.findCustomBottomByTitle(this, "撤回"));
                            }
                            player_black.dispatchCustomBottom();
                        }));
                    }
                    if (hisList.size() >= 2){
                        player_black.registerCustomBottom(new CustomBottom(this, "确认落子", player -> {
                            hisList.clear();
                            stepAdd();
                            noticeChangeMove();
                            if (player_black != null) {
                                player_black.clearCustomBottom();
                                player_black.dispatchCustomBottom();
                            }
                        }));
                    }
                }
            }
            else if (cur == 2) {
                if (player_white != null) {
                    if (hisList.size() == 0){
                        player_white.clearCustomBottom();
                        player_white.dispatchCustomBottom();
                    }
                    if (hisList.size() >= 1){
                        player_white.registerCustomBottom(new CustomBottom(this, "撤回", player -> {
                            restoreHis();
                            noticeAllRefreshGameInfo();
                            player_white.removeCustomBottom(player_white.findCustomBottomByTitle(this, "确认落子"));
                            if (hisList.size() == 0) {
                                player_white.removeCustomBottom(player_white.findCustomBottomByTitle(this, "撤回"));
                            }
                            player_white.dispatchCustomBottom();
                        }));
                    }
                    if (hisList.size() >= 2){
                        player_white.registerCustomBottom(new CustomBottom(this, "确认落子", player -> {
                            hisList.clear();
                            stepAdd();
                            noticeChangeMove();
                            if (player_white != null) {
                                player_white.clearCustomBottom();
                                player_white.dispatchCustomBottom();
                            }
                        }));
                    }
                }
            }
        }
    }


    protected void updateTempPointSigns() {
        tempPointSigns.clear();
        //新落子提示
        if (firstPoint != null && secondPoint != null) {
            tempPointSigns.add(new GroundSign(getIndex(firstPoint[0], firstPoint[1]), ColorCost.TRANSPARENT, ColorCost.NEW_PUT_POINT, 1.0f, 0, 0));
            tempPointSigns.add(new GroundSign(getIndex(secondPoint[0], secondPoint[1]), ColorCost.TRANSPARENT, ColorCost.NEW_PUT_POINT, 1.0f, 0, 0));
        }
        else if (firstPoint != null) {
            tempPointSigns.add(new GroundSign(getIndex(firstPoint[0], firstPoint[1]), ColorCost.TRANSPARENT, ColorCost.NEW_PUT_POINT, 1.0f, 0, 0));
        }

        if (state == 1) {
            beauti1(); //绘制第二部落子时的两个星光
        }
        else {
            beauti(lastPoint.get(0)[0], lastPoint.get(0)[1]); //绘制第一步单个星光
        }

    }

    private void beauti(int row, int col) {
        List<Integer> indexes = new ArrayList<Integer>();

        for (int i = 0; i < curGrids.length; i++) {
            for (int j = 0; j < curGrids[0].length; j++) {
                if (row - i == col - j || row - i == j - col || i == row || j == col) {
                    if (curGrids[i][j] == 0) {
                        indexes.add(getIndex(i, j));
                    }
                }
            }
        }

        tempPointSigns.add(new ColorSign(indexes, STAR_LIGHT_COLOR));
    }

    private void beauti1() {
        int row, col;
        List<Integer> indexes = new ArrayList<Integer>();
        for (int in = 0; in < 2; in++) {
            row = lastPoint.get(in)[0];
            col = lastPoint.get(in)[1];

            for (int i = 0; i < curGrids.length; i++) {
                for (int j = 0; j < curGrids[0].length; j++) {
                    if (row - i == col - j || row - i == j - col || i == row || j == col) {
                        if (curGrids[i][j] == 0) {
                            indexes.add(getIndex(i, j));
                        }
                    }
                }
            }
        }
        List<Integer> distinctIndexes = new ArrayList<>(indexes.size());
        for (Integer index : indexes) {
            if (!distinctIndexes.contains(index)) {
                distinctIndexes.add(index);
            }
        }

        tempPointSigns.add(new ColorSign(distinctIndexes, STAR_LIGHT_COLOR));
    }

    /**
     * 记录上一步历史状态
     */
    public void recordHis() {
        if (step == 1 && state == 0) {
            hisList.clear();
        }
        else if (hisList.size() == 2) {
            hisList.clear();
        }
        hisList.add(new His(curGrids, firstPoint, secondPoint, lastPoint, state, tempPointSigns));
    }

    /**
     * 恢复上一步历史状态
     */
    public void restoreHis() {
        if (hisList.size() > 0) {
            His his = hisList.get(hisList.size() - 1);
            curGrids = his.curGrids;
            firstPoint = his.firstPoint;
            secondPoint = his.secondPoint;
            lastPoint = his.lastPoint;
            state = his.state;
            tempPointSigns = his.tempPointSigns;
            hisList.remove(hisList.size() - 1);
        }
    }

    /**
     * 记录上一步历史状态
     */
    private static class His {
        int[][] curGrids;
        int[] firstPoint;
        int[] secondPoint;
        List<int[]> lastPoint;
        int state;
        List<Sign> tempPointSigns;

        public His(int[][] curGrids, int[] firstPoint, int[] secondPoint, List<int[]> lastPoint, int state, List<Sign> tempPointSigns) {
            this.curGrids = GridsUtils.copyGrids(curGrids);
            this.firstPoint = firstPoint != null ? new int[]{firstPoint[0], firstPoint[1], firstPoint[2]} : null;
            this.secondPoint = secondPoint != null ? new int[]{secondPoint[0], secondPoint[1], secondPoint[2]} : null;
            if (lastPoint != null) {
                this.lastPoint = new ArrayList<>();
                for (int[] point : lastPoint) {
                    this.lastPoint.add(new int[]{point[0], point[1], point[2]});
                }
            }
            else {
                this.lastPoint = null;
            }
            this.state = state;
            this.tempPointSigns = new ArrayList<>(tempPointSigns);
        }
    }
}
